/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.comac.ins.common.core.exception.ServiceException;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.core.utils.StreamUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.core.utils.file.FileUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.common.oss.core.OssClient;
import com.comac.ins.common.oss.entity.UploadResult;
import com.comac.ins.common.oss.enumd.AccessPolicyType;
import com.comac.ins.common.oss.factory.OssFactory;
import com.comac.ins.isfd.domain.IsfdModel;
import com.comac.ins.isfd.domain.bo.IsfdModelBo;
import com.comac.ins.isfd.domain.vo.*;
import com.comac.ins.isfd.mapper.ModelMapper;
import com.comac.ins.isfd.rpc.xuelang.XueLangRpcUtils;
import com.comac.ins.isfd.rpc.xuelang.bo.XueLangRenderBo;
import com.comac.ins.isfd.rpc.xuelang.bo.XueLangRenderExtraBo;
import com.comac.ins.isfd.rpc.xuelang.constants.enums.XueLangRenderFileTypeEnum;
import com.comac.ins.isfd.service.IIsfdMeshModelStructureDefinitionService;
import com.comac.ins.isfd.service.IIsfdModelService;
import com.comac.ins.isfd.util.DateUtils;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 模型库service层接口实现层
 *
 * @author hxloongs
 * @date 2024-7-1
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class IsfdModelServiceImpl implements IIsfdModelService {

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private IIsfdMeshModelStructureDefinitionService structureDefinitionService;

    @Autowired
    private XueLangRpcUtils xueLangRpcUtils;

    @Value("${evn.evnType}")
    private String evnType;
    @Override
    public List<ModelCountObjectVo> listCount() {
        List<ModelCountObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.select("file_suffix", "COUNT(*) as total_count");
        queryWrapper.groupBy("file_suffix");
        List<Map<String, Object>> list = modelMapper.selectMaps(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach((m -> {
                result.add(new ModelCountObjectVo((String) m.get("file_suffix"), (Long) m.get("total_count")));
            }));
        }
        return result;
    }

    @Override
    public List<ModelCountResultObjectVo> listApplicableCountByField(String field) {
        List<ModelCountResultObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        String modelColumn = "applicable_models";
        queryWrapper.select(field, "COUNT(*) as total_count", modelColumn);
        queryWrapper.groupBy(field, modelColumn);

        List<Map<String, Object>> list = modelMapper.selectMaps(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach((m -> {
                result.add(new ModelCountResultObjectVo(null, (String) m.get(field), (String) m.get(modelColumn), (Long) m.get("total_count")));
            }));
        }
        return result;
    }

    @Override
    public List<ModelCountResultObjectVo> listTimeCount(String field, Date startTime, Date endTime) {
        List<ModelCountResultObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        // 判断 field 是否为空，如果为空则不按该字段分组
        if (StringUtils.isEmpty(field)) {
            queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m') as month", "COUNT(*) as total_count");
            queryWrapper.groupBy("month");
        } else {
            queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m') as month", field + " as field_value", "COUNT(*) as total_count");
            queryWrapper.groupBy("month", "field_value");
        }

        if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
            queryWrapper.between("create_time", startTime, endTime);
        } else if (Objects.nonNull(startTime)) {
            queryWrapper.ge("create_time", startTime);
        } else if (Objects.nonNull(endTime)) {
            queryWrapper.le("create_time", endTime);
        }

        List<Map<String, Object>> list = modelMapper.selectMaps(queryWrapper);

        // 获取指定时间范围内的所有月份
        List<String> allMonths = DateUtils.getAllMonthsBetween(startTime, endTime);
        Set<String> fieldValues = list.stream()
            .filter(m -> m.get("field_value") != null)
            .map(m -> (String) m.get("field_value"))
            .collect(Collectors.toSet());

        // 如果没有指定 field，只用月份显示
        if (StringUtils.isEmpty(field)) {
            allMonths.forEach(month -> {
                Long count = list.stream()
                    .filter(m -> month.equals(m.get("month")))
                    .map(m -> (Long) m.get("total_count"))
                    .findFirst()
                    .orElse(0L);
                result.add(new ModelCountResultObjectVo(month, "", null, count));
            });
        } else {
            // 对每个月和每个字段值进行组合，确保没有数据的组合也显示 totalCount=0
            for (String month : allMonths) {
                for (String fieldValue : fieldValues) {
                    Long count = list.stream()
                        .filter(m -> month.equals(m.get("month")) && fieldValue.equals(m.get("field_value")))
                        .map(m -> (Long) m.get("total_count"))
                        .findFirst()
                        .orElse(0L);
                    result.add(new ModelCountResultObjectVo(month, fieldValue, null, count));
                }
            }
        }
        return result;
    }


    @Override
    public IsfdModelVo getById(Long modelId) {
        return modelMapper.selectVoById(modelId);
    }

    @Override
    public TableDataInfo<IsfdModelVo> queryPageList(IsfdModelBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<IsfdModel> lqw = buildQueryWrapper(bo, pageQuery);
        Page<IsfdModelVo> result = modelMapper.selectVoPage(pageQuery.build(), lqw);
        List<IsfdModelVo> filterResult = new ArrayList<>();
        if(evnType.equals("red")){
            filterResult = StreamUtils.toList(result.getRecords(), this::SignUrl);
        }else{
            filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl);
        }
        result.setRecords(filterResult);
        return TableDataInfo.build(result);
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // todo
            // 做一些业务上的校验,判断是否需要校验
        }
        List<IsfdModel> list = modelMapper.selectBatchIds(ids);
        for (IsfdModel isfdModel : list) {
            OssClient storage = OssFactory.instance(isfdModel.getService());
            storage.delete(isfdModel.getUrl());
        }
        return modelMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public IsfdModelVo save(MultipartFile file, IsfdModelBo isfdModelBo) {
        String originalFileName = file.getOriginalFilename();
        String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length());
        OssClient storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
        // 保存文件信息
        return saveModelDetail(originalFileName, suffix, storage.getConfigKey(), uploadResult, isfdModelBo);
    }

    @NotNull
    private IsfdModelVo saveModelDetail(String originalfileName, String suffix, String configKey,
                                        UploadResult uploadResult, IsfdModelBo isfdModelBo) {
        IsfdModel isfdModel = new IsfdModel();
        isfdModel.setUrl(uploadResult.getUrl());
        isfdModel.setFileSuffix(suffix);
        isfdModel.setFileName(uploadResult.getFilename());
        isfdModel.setOriginalName(originalfileName);
        isfdModel.setService(configKey);
        isfdModel.setModelName(isfdModelBo.getModelName());
        isfdModel.setModelType(isfdModelBo.getModelType());
        isfdModel.setApplicableModels(isfdModelBo.getApplicableModels());
        isfdModel.setModelSeries(isfdModelBo.getModelSeries());
        isfdModel.setLoadConditions(isfdModelBo.getLoadConditions());
        isfdModel.setModelScope(isfdModelBo.getModelScope());
        isfdModel.setBusinessScenarios(isfdModelBo.getBusinessScenarios());
        isfdModel.setModelDescription(isfdModelBo.getModelDescription());
        isfdModel.setSourceMethods(isfdModelBo.getSourceMethods());
        modelMapper.insert(isfdModel);
        IsfdModelVo isfdModelVo = MapstructUtils.convert(isfdModel, IsfdModelVo.class);
        return this.matchingUrl(isfdModelVo);
    }

    @Override
    public void download(Long modelId, HttpServletResponse response) throws IOException {
        IsfdModelVo isfdModelVo = this.getById(modelId);
        if (ObjectUtil.isNull(isfdModelVo)) {
            throw new ServiceException("文件数据不存在!");
        }
        FileUtils.setAttachmentResponseHeader(response, isfdModelVo.getOriginalName());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
        OssClient storage = OssFactory.instance(isfdModelVo.getService());
        long contentLength = storage.download(isfdModelVo.getFileName(), response.getOutputStream());
        response.setContentLengthLong(contentLength);
    }
    private LambdaQueryWrapper<IsfdModel> buildQueryWrapper(IsfdModelBo bo, PageQuery pageQuery) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<IsfdModel> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getModelName()), IsfdModel::getModelName, bo.getModelName());
        lqw.like(StringUtils.isNotBlank(bo.getModelType()), IsfdModel::getModelType, bo.getModelType());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            IsfdModel::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.eq(StringUtils.isNotBlank(bo.getBusinessScenarios()), IsfdModel::getBusinessScenarios, bo.getBusinessScenarios());
        return lqw;
    }


    private IsfdModelVo matchingUrl(IsfdModelVo modelVo) {
        OssClient storage = OssFactory.instance(modelVo.getService());
        // 仅修改桶类型为 private 的URL，临时URL时长为120s
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
            modelVo.setUrl(storage.getPrivateUrl(modelVo.getFileName(), 120));
        }
        return modelVo;
    }
    private IsfdModelVo SignUrl (IsfdModelVo modelVo) {
        OssClient storage = OssFactory.instance(modelVo.getService());
        modelVo.setUrl(storage.OssSignedUrl(modelVo.getFileName()));
        return modelVo;
    }

    @Override
    public Boolean insertByBo(IsfdModelBo bo) {
        // 校验参数
        checkParams(bo);
        IsfdModel add = MapstructUtils.convert(bo, IsfdModel.class);
        return modelMapper.insert(add) > 0;
    }

    @Override
    public IsfdModelManagementRenderingResultVo loadModel(Long id) {
        IsfdModelVo isfdModelVo = this.getById(id);
        if (isfdModelVo == null) {
            throw new BaseException("模型库不存在，请确认后重试！");
        }
        String url = isfdModelVo.getUrl();
        if (StringUtils.isBlank(url)) {
            throw new BaseException("模型库未上传文件，请确认后重试！");
        }
        String fileName = isfdModelVo.getFileName();
        XueLangRenderFileTypeEnum xueLangRenderFileTypeEnum = XueLangRenderFileTypeEnum.checkFileNameSuffix(fileName);
        if (xueLangRenderFileTypeEnum == null) {
            throw new BaseException("精细模型管理模型库文件格式不正确，请确认是否是zip或者bdf格式！");
        }

        // url加签
        IsfdModelVo targetVo = null;
        if (evnType.equals("red")) {
            targetVo = this.SignUrl(isfdModelVo);
        } else {
            targetVo = this.matchingUrl(isfdModelVo);
        }

        XueLangRenderBo xueLangRenderBo = new XueLangRenderBo();
        XueLangRenderExtraBo extraBo = new XueLangRenderExtraBo();
        xueLangRenderBo.setUrl(targetVo.getUrl());
        xueLangRenderBo.setType(XueLangRenderFileTypeEnum.BDF.getValue());
        if(xueLangRenderFileTypeEnum.getValue().endsWith(XueLangRenderFileTypeEnum.ZIP.getValue())){
            xueLangRenderBo.setEntryFile(isfdModelVo.getIndexFileName());
            extraBo.setTaskName(isfdModelVo.getModelName());
        }
        xueLangRenderBo.setEntryFile(isfdModelVo.getIndexFileName());
        extraBo.setModelNumber(isfdModelVo.getModelNumber());
        extraBo.setModelName(isfdModelVo.getApplicableModels());
        extraBo.setSectionNumbers(isfdModelVo.getSectionNumbers());
        extraBo.setSectionNames(isfdModelVo.getModelScope());
        xueLangRenderBo.setExtra(extraBo);
        //调用第三方团队接口获取renderUrl
        String renderUrl = xueLangRpcUtils.render(xueLangRenderBo);
//        String renderUrl = "www.baidu.com";
        IsfdModelManagementRenderingResultVo result = new IsfdModelManagementRenderingResultVo();
        result.setRenderUrl(renderUrl);
        return result;
    }

    private void checkParams(IsfdModelBo bo) {
        // 机型编号校验
        String modelNumber = bo.getModelNumber();
        if (StringUtils.isEmpty(modelNumber)) {
            throw new BaseException("机型编号不能为空!");
        }
        // 调用 getOrCreate 方法
        IsfdMeshModelStructureDefinitionVo modelDefinitionVo = structureDefinitionService.getOrCreate(modelNumber, null, null);
        // 可以在这里做后续处理，比如日志或返回结果收集
        log.info("新增/获取机型: {}", modelDefinitionVo.getName());

        // 部段编号校验
        String sectionNumbers = bo.getSectionNumbers();
        if(StringUtils.isEmpty(sectionNumbers)) {
            throw new BaseException("部段编号不能为空!");
        }
        String[] sectionNumberArr = sectionNumbers.split(",");
        for (String sectionNumber : sectionNumberArr) {
            sectionNumber = sectionNumber.trim(); // 去掉首尾空格
            if (StringUtils.isNotBlank(sectionNumber)) {
                // 调用 getOrCreate 方法，假设 modelNumber 已经有
                IsfdMeshModelStructureDefinitionVo sectionDefinitionVo = structureDefinitionService.getOrCreate(modelNumber, sectionNumber, null);
                // 可以在这里做后续处理，比如日志或返回结果收集
                log.info("新增/获取部段: {}", sectionDefinitionVo.getName());
            }
        }

    }
}
